--手动平面配平提示
printError("Please adjust horizontal center first!")
--转速控制器绑定初始化
local pitchcontrol = peripheral.wrap("back")
local yawcontrol = peripheral.wrap("top")
pitchcontrol.setTargetSpeed(0)
yawcontrol.setTargetSpeed(0)
--函数
function sec(i)
    local seci = 1 / math.cos(math.rad(i))
    return seci
end
function tan(i)
    local tani = math.tan(math.rad(i))
    return tani
end
function round(input , num)
    local remain = input % num
    if remain < 0 then
        return input - remain - num
    elseif remain > 0 then
        return input - remain
    else
        return input
    end
end
--炮管长度输入
local k = nil
print("Import barrel length:(From cannon mount to the end of barrel)")
repeat
    k = tonumber(io.read())
    if type(k) ~= "number" then
        printError("Wrong format, please try again.")
        k = nil
    elseif k < 1 then
        printError("Out of range, please try again.")
        k = nil
    elseif k % 1 ~= 0 then
        printError("Wrong format, please try again.")
        k = nil
    end
until k ~= nil
--发射药装药输入（用于瓦基大冒险高装药）
local n = nil
print("Import powder power:")
repeat
    n = tonumber(io.read())
    if type(n) ~= "number" then
        printError("Wrong format, please try again.")
        n = nil
    elseif n < 1 then
        printError("Out of range, please try again.")
        n = nil
    elseif n % 1 ~= 0 then
        printError("Wrong format, please try again.")
        n = nil
    end
until n ~= nil
--垂直修正
local ycor = nil
print("Import Y correction:")
repeat
    ycor = tonumber(io.read())
    if type(ycor) ~= "number" then
        printError("Wrong format, please try again.")
        ycor = nil
    elseif ycor % 1 ~= 0 then
        printError("Wrong format, please try again.")
        ycor = nil
    end
until ycor ~= nil
--俯仰偏航参考方向修正
local pitchcons = nil
print("Import pitch correction:(+-1)")
repeat
    pitchcons = tonumber(io.read())
    if type(pitchcons) ~= "number" then
        printError("Wrong format, please try again.")
        pitchcons = nil
    elseif pitchcons ~= 1 and pitchcons ~= -1 then
        printError("Wrong format, please try again.")
        pitchcons = nil
    end
until pitchcons ~= nil
local yawcons = nil
print("Import yaw correction:(+-1)")
repeat
    yawcons = tonumber(io.read())
    if type(yawcons) ~= "number" then
        printError("Wrong format, please try again.")
        yawcons = nil
    elseif yawcons ~= 1 and yawcons ~= -1 then
        printError("Wrong format, please try again.")
        yawcons = nil
    end
until yawcons ~= nil
local targetpos = { x = nil , y = nil , z = nil }
local currentpitch = 0
local correction = false

--主功能段

while true do
    ::start::
    --获取船体重心世界坐标
    local pos = ship.getWorldspacePosition()
    --获取船体偏航
    local yaw = ship.getYaw()
    --炮管轴世界坐标
    local cannonpos = { x = pos.x , y = pos.y + ycor , z = pos.z }
    --自动修正后允许变换目标
    if correction == false then
        print("Enter target position:")
        targetpos.x = io.read() + 0.5
        targetpos.y = io.read() + 0.5
        targetpos.z = io.read() + 0.5
    else
        print("Auto correcting.")
    end
    --炮塔对目标世界坐标系相对距离
    local delta = {
        x = targetpos.x - cannonpos.x ,
        y = targetpos.y - cannonpos.y ,
        z = targetpos.z - cannonpos.z
    }
    --直线水平距离
    local w = math.sqrt(delta.x ^ 2 + delta.z ^ 2)
    --俯仰计算
    local cannonpitch = nil
    local miss = 0.2
    repeat
        for i = 60 , -10 , -0.375 do
            local y_ccl = ((5 * sec(i) / n) + tan(i)) * w + 500 * math.log(1 - (w * sec(i) - k) / (100 * n)) - 5 * k / n
            if math.abs(delta.y - y_ccl) <= miss and miss < 2 then --误差内选取
                cannonpitch = i
                break
            elseif miss >= 2 then --误差外返回信息
                cannonpitch = "out of range"
                print("Negative, out of range.")
                break
            end
        end
        miss = miss + 0.2
    until cannonpitch ~= nil
    if cannonpitch == "out of range" then
        goto start
    end
    --偏航计算
    local cannonyaw = math.deg(math.atan2(delta.z , delta.x))
    if cannonyaw > 0 then
        cannonyaw = cannonyaw - 180
    else
        cannonyaw = cannonyaw + 180
    end
    cannonyaw = -cannonyaw + 90
    --运动输出
    local deltayaw = cannonyaw - math.deg(yaw)
    if deltayaw > 180 then
        deltayaw = deltayaw - 360
    elseif deltayaw < -180 then
        deltayaw = deltayaw + 360
    end
    local deltapitch = cannonpitch - currentpitch
    local pitchoutput = pitchcons * math.floor(deltapitch / 0.375 + 0.5)
    local yawoutput = yawcons * math.floor(deltayaw / 3 + 0.5)
    pitchcontrol.setTargetSpeed(pitchoutput)
    yawcontrol.setTargetSpeed(yawoutput)
    currentpitch = currentpitch + deltapitch
    sleep(0.4)
    pitchcontrol.setTargetSpeed(0)
    yawcontrol.setTargetSpeed(0)
    --偏航误差确认
    yaw = math.deg(ship.getYaw())
    if math.abs(yaw - cannonyaw) > 0.5 and yawoutput ~= 0 then
        correction = true
    else
        correction = false
        redstone.setOutput("bottom" , true)
        printError("FIRE!")
        sleep(0.1)
        redstone.setOutput("bottom" , false)
    end
end
